using System;
using Sce.PlayStation.Core;

namespace Nyanimals
{
	public class CMovingObject : CBaseObject
	{
		protected Matrix4 localMatrix; 
		protected Vector3 worldPivot;
		protected Vector3 scale;
		protected Vector3 position;
		protected Vector3 velocity;
		protected float speed;
		
        public Vector3 Scale
        {
            get { return scale;}
            set { scale = value;}
        }
        public float ScaleAll
        {
            set { scale.X = scale.Y = scale.Z = value;}
        }
        
		public virtual Vector3 Position
		{
			get 
			{
				position = WorldMatrix.AxisW;
				return position;
			}
            set 
            {
                Matrix4 tempWorld = context.WorldMatrix;
                position = tempWorld.AxisW = value;
                Context.WorldMatrix = tempWorld;
            }
		}
		public Vector3 Pivot
		{
			get { return worldPivot;}
			set { worldPivot = value;}
		}
		public Matrix4 LocalMatrix
		{
			get 
			{ 
				return localMatrix;
			}
			set 
			{ 
				localMatrix = value;
				position = localMatrix.AxisW;
			}
		}
		
		
		
		public CMovingObject() : base()
		{
			localMatrix = Matrix4.Identity;
			velocity = Vector3.Zero;	
			worldPivot = Vector3.Zero;
            scale = Vector3.One;
			//worldMatrix = Matrix4.Identity;
			speed = 10.0f;
			
		}
		
		public float Speed
		{
			get { return speed;}
			set { speed = value;}
		}
		public Vector3 Velocity
		{
			get { return velocity;}
			set { velocity = value;}
		}
		public float VelocityX
		{
			get { return velocity.X;}
			set { velocity.X = value;}
		}
		public float VelocityY
		{
			get { return velocity.Y;}
			set { velocity.Y = value;}
		}
		public float VelocityZ
		{
			get { return velocity.Z;}
			set { velocity.Z = value;}
		}
		
		// NOTE: TODO: This logic needs tested....
		private void RotateBy(Matrix4 rot)
		{
			//localMatrix.AxisW = Vector3.Zero;
			localMatrix = localMatrix * rot;
		}
		
		private void MoveBy(Vector3 vec)
		{
			localMatrix.AxisW += vec;
		}
		private void MoveBy(float x, float y, float z)
		{
			MoveBy(new Vector3(x, y, z));
		}
		
		// orientation Setters
		public void SetXAxis(Vector3 vec)
		{
			localMatrix.AxisX = vec;
		}
		public void SetYAxis(Vector3 vec)
		{
			localMatrix.AxisY = vec;
		}
		public void SetZAxis(Vector3 vec)
		{
			localMatrix.AxisZ = vec;
		}
		
		// Local Rotations
		public void RotateLocalX(float degree)
		{
			Vector3 local = localMatrix.AxisX;
			Matrix4 Rot = Matrix4.RotationAxis(local, FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		public void RotateLocalY(float degree)
		{
			Vector3 local = localMatrix.AxisY;
			Matrix4 Rot = Matrix4.RotationAxis(local, FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		public void RotateLocalZ(float degree)
		{
			Vector3 local = localMatrix.AxisZ;
			Matrix4 Rot = Matrix4.RotationAxis(local, FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		
		// Local Translations
		public void TranslateLocal(Vector3 delta, bool limitY = false)
		{
			TranslateLocalX(delta.X, limitY);
			TranslateLocalY(delta.Y, limitY);
			TranslateLocalZ(delta.Z, limitY);
		}
		public void TranslateLocalX(float delta, bool limitY = false)
		{
			Vector3 translate = localMatrix.AxisX;
			
			if(limitY)
			{
				translate.Y = 0.0f;
				translate = translate.Normalize();
			}
			Matrix4 transMatrix = Matrix4.Translation(translate * delta);
			localMatrix = transMatrix * localMatrix;
		}
		public void TranslateLocalY(float delta, bool limitY = false)
		{
			Vector3 translate = localMatrix.AxisY;
			
			if(limitY)
			{
				translate.Y = 0.0f;
				translate = translate.Normalize();
			}
			Matrix4 transMatrix = Matrix4.Translation(translate * delta);
			localMatrix = transMatrix * localMatrix;
		}
		public void TranslateLocalZ(float delta, bool limitY = false)
		{
			Vector3 translate = localMatrix.AxisZ;
			
			if(limitY)
			{
				translate.Y = 0.0f;
				translate = translate.Normalize();
			}
			Matrix4 transMatrix = Matrix4.Translation(translate * delta);
			localMatrix = transMatrix * localMatrix;
		}
		
		// Global rotations
		public void RotateGlobalX(float degree)
		{
			Matrix4 Rot = Matrix4.RotationX(FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		public void RotateGlobalY(float degree)
		{
			Matrix4 Rot = Matrix4.RotationY(FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		public void RotateGlobalZ(float degree)
		{
			Matrix4 Rot = Matrix4.RotationZ(FMath.Radians(degree));
			
			RotateBy(Rot);
		}
		
		// Global Translations
		public void TranslateGlobal(Vector3 delta)
		{
			TranslateGlobalX(delta.X);
			TranslateGlobalY(delta.Y);
			TranslateGlobalZ(delta.Z);
		}
		public void TranslateGlobalX(float delta)
		{
			Vector3 axis = localMatrix.AxisW;
			axis.X += delta;
						
			Matrix4 transMatrix = Matrix4.Translation(axis * delta);
			localMatrix = localMatrix * transMatrix;
		}
		public void TranslateGlobalY(float delta)
		{
			Vector3 axis = localMatrix.AxisW;
			axis.Y += delta;
			
			Matrix4 transMatrix = Matrix4.Translation(axis * delta);
			localMatrix = localMatrix * transMatrix;
		}
		public void TranslateGlobalZ(float delta)
		{
			Vector3 axis = localMatrix.AxisW;
			axis.Z += delta;
			
			Matrix4 transMatrix = Matrix4.Translation(axis * delta);
			localMatrix = localMatrix * transMatrix;
		}
		
		// Other nifty thingers
		public void LookAt(ref CMovingObject obj, Vector3 up)
		{
			LookAt(obj.WorldMatrix, up);
		}
		public void LookAt(Matrix4 mat, Vector3 up)
		{
			LookAt(mat.AxisW, up);
		}
		public void LookAt(Vector3 pos, Vector3 up)
		{
			if(pos == localMatrix.AxisW)
			{
				return;
			}
			/*
			Matrix4 lookAt = Matrix4.LookAt(localMatrix.AxisW, pos, up);
			Matrix4 position = Matrix4.Translation(localMatrix.AxisW);
			localMatrix = position * lookAt;
			*/
			// ZAxis
			Vector3 newZ = pos - Position;
			newZ = newZ.Normalize();
			
			// XAxis
			Vector3 newX = up.Cross(newZ);
			newX = newX.Normalize();
			
			// YAxis
			Vector3 newY = newZ.Cross(newX);
			newX.Normalize();
			
			// Put Together
			Matrix4 orientation = new Matrix4(newX, newY, newZ, Vector3.Zero);
			Matrix4 trans = Matrix4.Translation(localMatrix.AxisW);
			localMatrix = trans * orientation;
			
		}
		
		public override ObjectTypes Type
		{
			get { return ObjectTypes.Moving_Object;}
		}
		
		public override void Input()
		{
		}
		public override void Update(float deltaTime)
		{		
			
			Matrix4 pivotPoint = Matrix4.Translation(Pivot);			
            Matrix4 scaleMat = Matrix4.Scale(scale);
            
			WorldMatrix = pivotPoint * localMatrix * scaleMat;
			//localMatrix = Matrix4.Identity;
			
		}
		public override bool HandleCollision(ref CBaseObject Obj)
		{
			return false;
		}

        public override void Init ()
        {
        }

        public override void Shutdown ()
        {
        }
	}
}

